﻿using Dyao.Book.Application;
using Dyao.Book.Core;
using Dyao.Book.Repository.Shared;
using Foundation.AutoMapper;
using Foundation.Caching;
using Foundation.Core;
using Foundation.EntityFrameworkCore;
using Foundation.EntityFrameworkCore.SqlServer;
using Foundation.IdCreate;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Newtonsoft.Json;

namespace Dyao.Book.Web.Extensions
{
    public static class ServiceCollectionExtensions
    {
        /// <summary>
        /// 添加跨域
        /// </summary>
        /// <param name="services"></param>
        /// <param name="allowSpecificOrigins"></param>
        public static void AddCors(this IServiceCollection services, string allowSpecificOrigins = "DataCors")
        {
            services.AddCors(options =>
            {
                options.AddPolicy(name: allowSpecificOrigins,
                                  builder =>
                                  {
                                      builder.AllowAnyOrigin()
                                      .AllowAnyMethod()
                                      .AllowAnyHeader()
                                      .WithMethods("GET", "POST", "HEAD", "PUT", "DELETE", "OPTIONS");
                                  });
            });
        }

        /// <summary>
        /// Db Context Extensions
        /// </summary>
        /// <param name="services">IOC</param>
        /// <param name="configuration">配置对象</param>
        public static void AddDbContext(this IServiceCollection services, IConfiguration configuration)
        {
            services.TryAddTransient<DataDbContext>();
            services.AddFoundationDbContext<DataDbContext>(options =>
            {
                options.AddDefaultRepositories(true);
            });

            services.Configure<FoundationEntityOptions>(options => { });

            // 默认数据源
            services.Configure<DbConnectionOptions>(options =>
            {
                options.ConnectionStrings.Add("DataConn", configuration.GetConnectionString("DataConn"));
                options.ConnectionStrings.Add("DataConnRead", configuration.GetConnectionString("DataConnRead"));
            });

            services.Configure<FoundationDbContextOptions>(options =>
            {
                options.UseSqlServer(optionsBuilder =>
                {
                    //optionsBuilder.UseCompatibilityLevel(120); // .NET Core 8 兼容低版本SQLSERVER
                });

                options.UseSqlServer<DataDbContext>(optionsBuilder =>   
                {
                    //optionsBuilder.UseCompatibilityLevel(120); // .NET Core 8 兼容低版本SQLSERVER
                });

            });
        }

        /// <summary>
        /// add mvc service
        /// </summary>
        /// <param name="services"></param>
        public static void AddMinimalMvc(this IServiceCollection services, Action<MvcOptions> mvcConfigure = null)
        {
            services.AddControllers(options =>
            {
                //注册
                //options.Filters.Add(typeof(UserPrincipalProcessFilterAttribute));
                //options.AddOutputFormatter();
                mvcConfigure?.Invoke(options);
            })
            .AddNewtonsoftJson(options =>
            {
                options.UseCamelCasing(true);//返回结果用Camel
                //options.UseMemberCasing();//返回结果以原结果返回

                var settings = options.SerializerSettings;
                settings.ContractResolver = new ExtensionDataContractResolver(new ExtensionDataContractResolverOptions()
                {
                    //IsConvetListToEmpty=false
                });
                settings.NullValueHandling = NullValueHandling.Include;
                settings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
            });

            services.PostConfigure<ApiBehaviorOptions>(o =>
            {
                //参数验证失败时
                o.InvalidModelStateResponseFactory = context =>
                {
                    var problemDetails = context.HttpContext?.RequestServices?.GetRequiredService<ProblemDetailsFactory>()
                     .CreateValidationProblemDetails(context.HttpContext, context.ModelState);

                    return new ObjectResult(problemDetails)
                    {
                        StatusCode = problemDetails.Status
                    };
                };
            });

            services.AddHttpContextAccessor();
        }

        /// <summary>
        /// Object Mapping Extensions
        /// </summary>
        /// <param name="services"></param>
        public static void AddObjectMapping(this IServiceCollection services, Action<AutoMapperOptions> configureAction = null)
        {
            services.Configure<AutoMapperOptions>(options =>
            {
                options.AddProfile<ModelMappingProfile>();

                configureAction?.Invoke(options);
            });
        }

        /// <summary>
        /// 添加缓存配置
        /// </summary>
        /// <param name="services"></param>
        public static void AddCustomCaching(this IServiceCollection services, IConfiguration configuration)
        {
            services.AddCollectCaching();

            services.AddEasyCaching(option =>
            {
                // local
                option.UseInMemory(configuration, "InMemoryCache");

                // distributed
                option.UseRedis(configuration, "RedisCache");

                // combine local with bus
                option.UseDistributeInMemory(configuration, "DistributedInMemoryCache");

                // combine local, distributed with bus
                option.UseHybrid(configuration, "DistributedMultiLevelCache");

                // use Redis bus
                option.WithRedisBus(configuration);

                // use json serialization
                option.WithJson("RedisDyao");
            });
        }

        /// <summary>
        /// 添加选项集合服务
        /// </summary>
        /// <param name="services"></param>
        /// <param name="configure"></param>
        public static void AddSelectCollection(this IServiceCollection services, Action<SelectCollectionServiceOptionsBuilder> configure = null)
        {

            services.TryAddTransient<ServiceMethodSelectCollectionUniOfWrokCreatorFactory>();
            services.TryAddTransient<ISelectTypeFilter, AssemblyISelectTypeFilter>();
            services.AddSelectCollectionService(builder =>
            {
                builder.AddTypeResultFilter(new EnumShortNameSelectResultFilter());

                builder.IsEnabledListingLoadAssembly = true;
                builder.AddAssemblyCongigure((b, assembly) =>
                {
                    if (!assembly.FullName.Contains("Dyao.")) return;

                    //只加载 Contract 程序集的常量类、枚举
                    if (assembly.FullName.Contains(".Contract"))
                    {
                        b.AddTypeSelectitems(assembly, new AssemblyISelectTypeFilter(b.Registrar));
                    }
                });

                //添加自定义选项集合服务
                builder.AddCustomItemsLoaderService(typeof(ApplicationModule).Assembly);

                if (configure != null)
                {
                    configure(builder);
                }
            });
        }

        /// <summary>
        /// 添加 id 创建服务
        /// </summary>
        /// <param name="services"></param>
        public static void AddIdCreate(this IServiceCollection services)
        {
            services.AddIdCreateService(createBuilder =>
            {
                createBuilder.AdddStoreConfigure(storeBuilder =>
                {
                    storeBuilder.RegisterConfiguration(typeof(ApplicationModule).Assembly);
                });
            });
        }
    }
}
